home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Taifun
/
Taifun 117 (1989-11-15)(Ossowski, Stefan)(DE)(PD).zip
/
Taifun 117 (1989-11-15)(Ossowski, Stefan)(DE)(PD).adf
/
AlarmingClock
/
AlarmingClock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-20
|
25KB
|
845 lines
/*
** alarming_clock -- by Brian Neal 6/24/89
**
** A simple clock program whoose alarm packs a punch! Be sure to
** crank up the stereo for this one. Illustrates the use of the
** timer and digitized sound playback.
** Compiled with Manx Aztec C v3.6
** cc -n alarming_clock
** ln -g alarming_clock isup -lc
*/
#include <intuition/intuition.h>
#include <functions.h>
#include <devices/audio.h>
#include <devices/timer.h>
#include <exec/memory.h>
#include <libraries/dos.h>
/* useful macros */
#define CHAR_WIDTH (font -> tf_XSize)
#define CHAR_HEIGHT (font -> tf_YSize)
#define WIN_WIDTH 200 /* window constants */
#define WIN_HEIGHT 60
#define BUTT_WIDTH 50 /* gadget constants */
#define BUTT_HEIGHT 14
#define TEST 1 /* GadgetIDs */
#define ALARM 2
#define UP 3
#define DOWN 4
#define HRS_TEN 5
#define HRS_ONE 6
#define MIN_TEN 7
#define MIN_ONE 8
#define ARROW_WIDTH 16 /* arrow dimensions */
#define ARROW_HEIGHT 8
#define MAPRIGHT 0x00000006 /* masks for channel allocation */
#define MAPLEFT 0x00000009
#define SCREAM_PERIOD 400
#define SCREAM_LENGTH 12536 /* length (in bytes) of data file */
/* used CLI's List to get this */
#define POW_PERIOD 475
#define POW_LENGTH 23632
#define CLOCK_LEFT ((WIN_WIDTH - (5 * CHAR_WIDTH)) / 2)
#define CLOCK_TOP 12
#define ALARM_LEFT CLOCK_LEFT
#define ALARM_TOP 24
extern BOOL open_libraries();
extern struct Window *make_window();
extern void init_itext(), *copy_chip();
void shut_down(), init_sounds(), shut_down_audio(), display_time(),
shut_down_timer(), send_time_request(), init_arrow(), init_image(),
set_up_display(), sound_alarm(), display_alarm(),
turn_off_alarm(), init_digit(), adjust_alarm();
UBYTE init_audio();
BOOL read_data(), init_timer(), set_up_window(), time_to_sound(),
set_up_gadgets();
struct IntuiText test_text, alarm_text, clock_face, alarm_face;
struct Gadget arrow[2];
struct Gadget digit[4];
struct Image arrow_image[2];
#define ARROW_BYTES 16
USHORT up_image[] = { 0x0000, 0x0180, 0x03c0, 0x07e0,
0x0ff0, 0x1ff8, 0x7ffe, 0x0000 };
USHORT down_image[] = { 0x0000, 0x7ffe, 0x1ff8, 0x0ff0,
0x07e0, 0x03c0, 0x0180, 0x0000 };
SHORT points[] = { -1, -1, BUTT_WIDTH, -1,
BUTT_WIDTH, BUTT_HEIGHT,
-1, BUTT_HEIGHT, -1, -1 };
struct Border butt_border =
{ 0, 0, /* LeftEdge, TopEdge */
3, 0, /* FrontPen, BackPen */
JAM1, /* DrawMode */
5, /* Count */
&points[0], /* XY */
NULL }; /* NextBorder */
struct Gadget test_button =
{ NULL, /* NextGadget */
20, -(BUTT_HEIGHT + 5), /* LeftEdge, TopEdge */
BUTT_WIDTH, BUTT_HEIGHT, /* Width, Height */
GADGHCOMP | GRELBOTTOM, /* Flags */
GADGIMMEDIATE | RELVERIFY, /* Activation */
BOOLGADGET, /* GadgetType */
(APTR) &butt_border, /* GadgetRender */
NULL, /* SelectRender */
&test_text, /* GadgetText */
0L, /* MutualExclude */
NULL, /* SpecialInfo */
TEST, /* GadgetID */
NULL }; /* UserData */
struct Gadget alarm_button =
{ &test_button,
-(BUTT_WIDTH + 20), -(BUTT_HEIGHT + 5),
BUTT_WIDTH, BUTT_HEIGHT,
GADGHCOMP | GRELRIGHT | GRELBOTTOM,
GADGIMMEDIATE | TOGGLESELECT,
BOOLGADGET,
(APTR) &butt_border,
NULL,
&alarm_text,
0L,
NULL,
ALARM,
NULL };
/* We are going to use topaz.font 80 */
struct TextAttr our_font =
{ (STRPTR) "topaz.font", /* ta_Name */
8, /* ta_YSize */
FS_NORMAL, /* ta_Style */
FPB_ROMFONT }; /* ta_Flags */
struct my_time /* hours in range of 0..24, minutes in 0..59 */
{
UBYTE hours, minutes;
};
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct TextFont *font = NULL;
void main()
{
struct Window *win = NULL;
struct IntuiMessage *msg;
struct IOAudio scream, pow;
UBYTE channel_mask;
UBYTE *scream_data = NULL, *pow_data = NULL;
struct timerequest time_req;
struct my_time current, alarm;
struct Gadget *gad;
ULONG class;
USHORT active_digit;
BOOL alarm_set, gad_images = FALSE;
if (!(open_libraries(33L, 33L)))
shut_down(10, win, scream_data, pow_data, gad_images);
if (!(font = (struct TextFont *) OpenFont(&our_font)))
shut_down(20, win, scream_data, pow_data, gad_images);
if (!(read_data(&scream_data, &pow_data)))
shut_down(30, win, scream_data, pow_data, gad_images);
if (!(gad_images = set_up_gadgets()))
shut_down(40, win, scream_data, pow_data, gad_images);
if (!set_up_window(&win))
shut_down(50, win, scream_data, pow_data, gad_images);
if ((channel_mask = init_audio(&scream)) == 0)
shut_down(60, win, scream_data, pow_data, gad_images);
init_sounds(&scream, &pow, channel_mask, scream_data, pow_data);
if (!(init_timer(&time_req)))
{
shut_down_audio(&scream, channel_mask);
shut_down(70, win, scream_data, pow_data, gad_images);
}
set_up_display(win, &clock_face, &alarm_face);
/* Give us a boost in priority */
SetTaskPri(FindTask(NULL), 20L);
alarm_set = FALSE;
active_digit = MIN_ONE;
alarm.hours = 0;
alarm.minutes = 0;
display_time(win, &clock_face, ¤t);
display_alarm(win, &alarm_face, alarm);
send_time_request(&time_req);
FOREVER
{
/*
* if our time request is back, update clock and restart the
* timer. If alarm is set, and it is that magic time, sound
* the alarm.
*/
if (GetMsg(time_req.tr_node.io_Message.mn_ReplyPort))
{
display_time(win, &clock_face, ¤t);
send_time_request(&time_req);
if ((time_to_sound(current, alarm)) && alarm_set)
sound_alarm(win, &scream, &pow);
}
/* Wait on timer and input from user via window */
Wait(1L << win -> UserPort -> mp_SigBit |
1L << time_req.tr_node.io_Message.mn_ReplyPort -> mp_SigBit);
while (msg = (struct IntuiMessage *) GetMsg(win -> UserPort))
{
class = msg -> Class;
gad = (struct Gadget *) msg -> IAddress;
ReplyMsg(msg);
switch (class)
{
case CLOSEWINDOW:
shut_down_timer(&time_req);
shut_down_audio(&scream, channel_mask);
shut_down(0, win, scream_data, pow_data, gad_images);
break;
case GADGETUP: /* has no meaning; set in gadgets */
break; /* only to let user see GADGHCOMP */
case GADGETDOWN:
switch(gad -> GadgetID)
{
case ALARM:
if (alarm_set)
{
turn_off_alarm(&alarm_button, win);
alarm_set = FALSE;
}
else
alarm_set = TRUE;
break;
case TEST:
sound_alarm(win, &scream, &pow);
break;
case UP:
case DOWN:
adjust_alarm(&alarm, active_digit, gad -> GadgetID);
display_alarm(win, &alarm_face, alarm);
break;
case HRS_TEN:
case HRS_ONE:
case MIN_TEN:
case MIN_ONE:
active_digit = gad -> GadgetID;
break;
}
break;
default:
break;
} /* switch */
} /* while */
} /* for(;;) */
} /* main */
/*
** shut_down()
** Frees up everything but audio and timer related activiy.
**/
void shut_down(code, win, scream, pow, gad_images)
WORD code;
struct Window *win;
UBYTE *scream, *pow;
BOOL gad_images;
{
struct IntuiMessage *msg;
if (gad_images)
{
FreeMem(arrow_image[0].ImageData, (ULONG) ARROW_BYTES);
FreeMem(arrow_image[1].ImageData, (ULONG) ARROW_BYTES);
}
if (pow)
FreeMem(pow, (ULONG) POW_LENGTH);
if (scream)
FreeMem(scream, (ULONG) SCREAM_LENGTH);
if (win)
{
while(msg = (struct IntuiMessage *) GetMsg(win -> UserPort))
ReplyMsg(msg);
CloseWindow(win);
}
if (font)
CloseFont(font);
if (GfxBase)
CloseLibrary(GfxBase);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
Exit((LONG) code);
}
/*
** shut_down_audio()
** Cleans up after using audio.device.
*/
void shut_down_audio(scream, channels_used)
struct IOAudio *scream;
UBYTE channels_used;
{
scream -> ioa_Request.io_Unit = (struct Unit *) channels_used;
CloseDevice(scream);
DeletePort(scream -> ioa_Request.io_Message.mn_ReplyPort);
/* remember, pow and scream shared the same reply port */
}
/*
** init_audio()
** Opens audio device and allocates a stereo pair of channels.
** Returns a mask of channels allocated, or 0 if error.
*/
UBYTE init_audio(iob)
struct IOAudio *iob;
{
UBYTE channel_map[4];
LONG error;
ULONG mask;
channel_map[0] = 0x03; /* channels 0 and 1 */
channel_map[1] = 0x05; /* channels 0 and 2 */
channel_map[2] = 0x0a; /* channels 3 and 1 */
channel_map[3] = 0x0c; /* channels 3 and 2 */
/* Get a reply port so the audio device can communicate with us */
if ((iob -> ioa_Request.io_Message.mn_ReplyPort
= CreatePort("ac", 0L)) == NULL)
return (0);
/* We are now going to be pigs and set our priority to the max. If
* successful, we hold exclusive access to our stereo pair of channels.
* Why don't we just set our priority lower, allocate channels, and then
* lock them? Because we don't intend to give up our access until
* we quit.
*/
iob -> ioa_Request.io_Message.mn_Node.ln_Pri = ADALLOC_MAXPREC;
iob -> ioa_Data = &channel_map[0];
iob -> ioa_Length = 4L;
error = OpenDevice(AUDIONAME, 0L, iob, 0L);
if (error == 0)
{
mask = (ULONG) iob -> ioa_Request.io_Unit;
return ((UBYTE) mask);
}
else
{
DeletePort(iob -> ioa_Request.io_Message.mn_ReplyPort);
return (0);
}
}
/*
** init_sounds()
** Initializes our IOAudio request blocks for sounding
** once. Attaches waveform data.
*/
void init_sounds(scream, pow, channel_mask, scream_data, pow_data)
struct IOAudio *scream, *pow;
UBYTE channel_mask;
UBYTE *scream_data, *pow_data;
{
scream -> ioa_Request.io_Unit = (struct Unit *)
((ULONG) channel_mask & MAPRIGHT);
scream -> ioa_Request.io_Command = CMD_WRITE;
scream -> ioa_Request.io_Flags = IOF_QUICK | ADIOF_PERVOL;
scream -> ioa_Data = scream_data;
scream -> ioa_Cycles = 1;
scream -> ioa_Period = SCREAM_PERIOD;
scream -> ioa_Length = (ULONG) SCREAM_LENGTH;
scream -> ioa_Volume = 64;
/* copy keys, ports, and above stuff */
*pow = *scream;
/* Now, more specifically... */
pow -> ioa_Request.io_Unit = (struct Unit *)
((ULONG) channel_mask & MAPLEFT);
pow -> ioa_Data = pow_data;
pow -> ioa_Period = POW_PERIOD;
pow -> ioa_Length = (ULONG) POW_LENGTH;
}
/*
** read_data()
** Read in digitized sound files, placing them into
** Chip memory. Note that the files are IFF, but treated as
** raw data. Hopefully, won't be able to hear the 'pop' as the
** header information is played. NOTE: Would be simple
** to skip over the header. A job for a future revision.
** Call AmigaDos directly, bypassing all that "ffunction" stuff.
** shut_down() is responsible for freeing up the allocated Chip
** memory, so don't have to worry about that here.
*/
BOOL read_data(screamptr, powptr)
UBYTE **screamptr, **powptr;
{
struct FileHandle *scream_file, *pow_file;
LONG scream_actual, pow_actual;
*screamptr = AllocMem((ULONG) SCREAM_LENGTH, MEMF_CHIP);
*powptr = AllocMem((ULONG) POW_LENGTH, MEMF_CHIP);
pow_file = Open("explosion.sound", MODE_OLDFILE);
scream_file = Open("scream.sound", MODE_OLDFILE);
if ((!scream_file) || (!pow_file) || (!(*screamptr)) || (!(*powptr)))
{
if (scream_file)
Close(scream_file);
if (pow_file)
Close(pow_file);
return (FALSE);
}
scream_actual = Read(scream_file, *screamptr, (LONG) SCREAM_LENGTH);
pow_actual = Read(pow_file, *powptr, (LONG) POW_LENGTH);
Close(scream_file);
Close(pow_file);
if ((scream_actual != SCREAM_LENGTH) || (pow_actual != POW_LENGTH))
return (FALSE);
else
return (TRUE);
}
/*
** init_timer()
** Initializes our time request and opens the timer
** device.
*/
BOOL init_timer(time_req)
struct timerequest *time_req;
{
/* obtain reply port so timer can signal us */
if (!(time_req -> tr_node.io_Message.mn_ReplyPort =
CreatePort("ac_timer", 0L)))
return (FALSE);
if (OpenDevice(TIMERNAME, UNIT_VBLANK, time_req, 0L) != NULL)
{
DeletePort(time_req -> tr_node.io_Message.mn_ReplyPort);
return (FALSE);
}
else
{
/* set up our time request so the timer will time time for us */
time_req -> tr_node.io_Command = TR_ADDREQUEST;
time_req -> tr_node.io_Flags = IOF_QUICK;
return (TRUE);
}
}
/*
** display_time()
** Outputs the current time to our window.
*/
void display_time(win, clock_face, current)
struct Window *win;
struct IntuiText *clock_face;
struct my_time *current;
{
struct DateStamp now;
SHORT hours, minutes;
static char time_buffer[7];
DateStamp(&now); /* get system time from AmigaDos */
hours = now.ds_Minute / 60;
minutes = now.ds_Minute % 60;
/* format our time display in the time_buffer */
sprintf(&time_buffer[0], "%02d:%02d", hours, minutes);
/* attach it to our IntuiText structure, and display it */
clock_face -> IText = (UBYTE *) &time_buffer[0];
PrintIText(win -> RPort, clock_face, 0L, 0L);
current -> hours = hours;
current -> minutes = minutes;
}
/*
** display_alarm()
** Outputs the current setting of the alarm to our window.
*/
void display_alarm(win, alarm_face, alarm)
struct Window *win;
struct IntuiText *alarm_face;
struct my_time alarm;
{
static char alarm_buffer[7];
sprintf(&alarm_buffer[0], "%02d:%02d", alarm.hours, alarm.minutes);
alarm_face -> IText = (UBYTE *) &alarm_buffer[0];
PrintIText(win -> RPort, alarm_face, 0L, 0L);
}
/*
** shut_down_timer()
** Releases access to the timer device.
*/
void shut_down_timer(time_req)
struct timerequest *time_req;
{
AbortIO(time_req);
CloseDevice(time_req);
DeletePort(time_req -> tr_node.io_Message.mn_ReplyPort);
}
/*
** send_time_request()
** Sends a message to the timer, telling it to signal us
** in five seconds. Thus our clock can never be off from the system
** clock by more than five seconds.
**
*/
void send_time_request(time_req)
struct timerequest *time_req;
{
time_req -> tr_time.tv_secs = 5L;
time_req -> tr_time.tv_micro = 0L;
BeginIO(time_req);
}
/*
** init_arrow()
** Initializes the alarm's set buttons.
*/
void init_arrow(arrow, id)
struct Gadget *arrow;
COUNT id;
{
arrow -> NextGadget = (id == 0) ? &arrow[1]
: &alarm_button;
arrow -> LeftEdge = (id == 0) ? (ALARM_LEFT - (ARROW_WIDTH + 6))
: (ALARM_LEFT + (CHAR_WIDTH * 5) + 6);
arrow -> TopEdge = ALARM_TOP;
arrow -> Width = ARROW_WIDTH;
arrow -> Height = ARROW_HEIGHT;
arrow -> Flags = GADGHCOMP | GADGIMAGE;
arrow -> Activation = GADGIMMEDIATE | RELVERIFY;
arrow -> GadgetType = BOOLGADGET;
arrow -> GadgetRender = (APTR) &arrow_image[id];
arrow -> SelectRender = NULL;
arrow -> GadgetText = NULL;
arrow -> MutualExclude = 0L;
arrow -> SpecialInfo = NULL;
arrow -> GadgetID = UP + id;
arrow -> UserData = NULL;
}
/*
** init_image()
** Initializes the alarm set button's images.
*/
void init_image(arrow, id)
struct Image *arrow;
COUNT id;
{
arrow -> LeftEdge = 0;
arrow -> TopEdge = 0;
arrow -> Width = ARROW_WIDTH;
arrow -> Height = ARROW_HEIGHT;
arrow -> Depth = 1;
arrow -> ImageData = (id == 0) ? &up_image[0] : &down_image[0];
arrow -> PlanePick = 2;
arrow -> PlaneOnOff = 0;
arrow -> NextImage = NULL;
}
/*
** init_digit()
** Initializes the alarm's digit gadgets.
*/
void init_digit(d, id)
struct Gadget *d;
UCOUNT id;
{
d -> NextGadget = (id < 3) ? &digit[id + 1] : &arrow[0];
if (id < 2)
d -> LeftEdge = ALARM_LEFT + (id * CHAR_WIDTH);
else
d -> LeftEdge = ALARM_LEFT + CHAR_WIDTH + (id * CHAR_WIDTH);
d -> TopEdge = ALARM_TOP;
d -> Width = CHAR_WIDTH;
d -> Height = CHAR_HEIGHT;
d -> Flags = GADGHCOMP;
d -> Activation = GADGIMMEDIATE | RELVERIFY;
d -> GadgetType = BOOLGADGET;
d -> GadgetRender = NULL;
d -> SelectRender = NULL;
d -> GadgetText = NULL;
d -> MutualExclude = 0L;
d -> SpecialInfo = NULL;
d -> GadgetID = HRS_TEN + id;
d -> UserData = NULL;
}
/*
** set_up_window()
** Hides the details of opening the window from
** main().
*/
BOOL set_up_window(win)
struct Window **win;
{
if (!(*win = make_window(100, 60, WIN_WIDTH, WIN_HEIGHT, -1, -1,
CLOSEWINDOW | GADGETUP | GADGETDOWN,
WINDOWCLOSE | ACTIVATE | WINDOWDRAG |
WINDOWDEPTH | SMART_REFRESH,
NULL, NULL, NULL,
NULL, NULL, 0, 0, 0, 0)))
return (FALSE);
SetFont((*win) -> RPort, font);
SetWindowTitles(*win, (UBYTE *) "Alarming Clock", NULL);
AddGList(*win, &digit[0], -1L, -1L, NULL);
RefreshGList(&digit[0], *win, NULL, -1L);
return (TRUE);
}
/*
** set_up_gadgets()
** Hides the details of initializing all of our gadgets
** from main(). Our gadget list looks like:
** digits -> arrows -> alarm_button -> test_button
*/
BOOL set_up_gadgets()
{
COUNT i;
init_itext(&test_text, 1, 9, 3, "TEST");
init_itext(&alarm_text, 1, 5, 3, "ALARM");
for (i = 0; i < 4; ++i)
init_digit(&digit[i], i);
for (i = 0; i < 2; ++i)
{
init_arrow(&arrow[i], i);
init_image(&arrow_image[i], i);
}
arrow_image[0].ImageData = copy_chip(&up_image[0], ARROW_BYTES);
arrow_image[1].ImageData = copy_chip(&down_image[0], ARROW_BYTES);
if ((arrow_image[0].ImageData) && (arrow_image[1].ImageData))
return (TRUE);
else
{
if (arrow_image[0].ImageData)
FreeMem(arrow_image[0].ImageData, (ULONG) ARROW_BYTES);
if (arrow_image[1].ImageData)
FreeMem(arrow_image[1].ImageData, (ULONG) ARROW_BYTES);
return (FALSE);
}
}
/*
** set_up_display()
** Hides the details of "drawing" our clock face from
** main().
*/
void set_up_display(win, clock_face, alarm_face)
struct Window *win;
struct IntuiText *clock_face, *alarm_face;
{
init_itext(clock_face, 1, CLOCK_LEFT, CLOCK_TOP, "");
init_itext(alarm_face, 3, ALARM_LEFT, ALARM_TOP, "");
clock_face -> DrawMode = JAM2; /* use both pens, so old junk */
alarm_face -> DrawMode = JAM2; /* gets erased when written on */
}
/*
** sound_alarm()
** Beeps screen, and brings window to the front.
** Sends off a scream request, waits for it to finish,
** then fires off the pow request. Waits for it to finish, then
** returns.
*/
void sound_alarm(win, scream, pow)
struct Window *win;
struct IOAudio *scream, *pow;
{
DisplayBeep(NULL); /* Beep everyone's screen, impolite */
WindowToFront(win); /* but hey, someone needs reminding */
BeginIO(scream);
WaitIO(scream);
BeginIO(pow);
WaitIO(pow);
}
/*
** time_to_sound()
** Returns true is current time == time alarm is supposed
** to go off.
*/
BOOL time_to_sound(current, alarm)
struct my_time current, alarm;
{
return ((current.hours == alarm.hours) &&
(current.minutes == alarm.minutes));
}
/*
** turn_off_alarm()
** Shuts off the alarm by deselecting the alarm gadget.
** Note that you can't simply change the gadget's flags and refresh,
** you have to remove it, change it's flags, add it, then refresh.
*/
void turn_off_alarm(alarm_button, win)
struct Gadget *alarm_button;
struct Window *win;
{
RemoveGadget(win, alarm_button);
alarm_button -> Flags &= ~SELECTED;
AddGadget(win, alarm_button, -1L);
RefreshGList(alarm_button, win, NULL, 1L);
}
/*
** adjust_alarm()
** When user clicks on arrows, we come here and adjust
** our alarm display. The variable active_digit keeps track of the
** digit being changed. This is a big mess!!
*/
void adjust_alarm(alarm, active_digit, direction)
struct my_time *alarm;
USHORT active_digit, direction;
{
switch(active_digit)
{
case HRS_TEN:
if (direction == UP)
{
if (alarm -> hours >= 14)
alarm -> hours = 0;
else
alarm -> hours += 10;
}
else
{
if (alarm -> hours < 9)
alarm -> hours = 23;
else
alarm -> hours -= 10;
}
break;
case HRS_ONE:
if (direction == UP)
alarm -> hours = (alarm -> hours + 1) % 24;
else
{
if (alarm -> hours == 0)
alarm -> hours = 23;
else
--alarm -> hours;
}
break;
case MIN_TEN:
if (direction == UP)
{
if (alarm -> minutes > 49)
alarm -> minutes = 0;
else
alarm -> minutes += 10;
}
else
{
if (alarm -> minutes < 10)
alarm -> minutes = 59;
else
alarm -> minutes -= 10;
}
break;
case MIN_ONE:
if (direction == UP)
alarm -> minutes = (alarm -> minutes + 1) % 60;
else
{
if (alarm -> minutes == 0)
alarm -> minutes = 59;
else
--alarm -> minutes;
}
break;
}
}